package com.campus.counseling.security;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Component
@RequiredArgsConstructor
public class JwtTokenUtil {
    private static final String SECRET_KEY = "your_secret_key_here";
    private static final long EXPIRATION_TIME = 86400000; // 24小时
    private static final long REMEMBER_EXPIRATION = 604800000; // 7天
    private static final Logger log = LoggerFactory.getLogger(JwtTokenUtil.class);

    private final UserDetailsService userDetailsService;

    // 生成token
    public String generateToken(Authentication authentication, boolean remember) {
        // 获取认证信息中的用户信息
        SecurityUser userDetails = (SecurityUser) authentication.getPrincipal();
        // 创建一个map，用于存储token中的信息
        Map<String, Object> claims = new HashMap<>();
        // 将用户名存入map中
        claims.put("sub", userDetails.getUsername());
        // 将当前时间存入map中
        claims.put("created", new Date());

        // 根据remember参数设置token的过期时间
        long expiration = remember ? REMEMBER_EXPIRATION : EXPIRATION_TIME;

        // 使用Jwts.builder()创建一个token
        return Jwts.builder()
                // 设置token中的信息
                .setClaims(claims)
                // 设置token的过期时间
                .setExpiration(new Date(System.currentTimeMillis() + expiration))
                // 使用HS512算法进行签名
                .signWith(SignatureAlgorithm.HS512, SECRET_KEY)
                // 生成token
                .compact();
    }

    // 从token中获取用户名
    public String getUsernameFromToken(String token) {
        // 如果token以"Bearer "开头，则去掉"Bearer "部分
        if (token.startsWith("Bearer ")) {
            token = token.substring(7);
        }
        try {
            // 从token中获取claims
            Claims claims = getClaimsFromToken(token);
            // 返回claims中的subject，即用户名
            return claims.getSubject();
        } catch (Exception e) {
            // 如果出现异常，则返回null
            return null;
        }
    }

    // 从token中获取Claims
    public Claims getClaimsFromToken(String token) {
        try {
            // 使用Jwts解析token，设置签名密钥，获取Claims
            return Jwts.parser()
                    .setSigningKey(SECRET_KEY)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            // 如果解析失败，抛出JwtException异常
            throw new JwtException("Invalid JWT token");
        }
    }

    // 验证token是否有效
    public boolean validateToken(String token, UserDetails userDetails) {
        // 如果token以"Bearer "开头，则去掉"Bearer "部分
        if (token.startsWith("Bearer ")) {
            token = token.substring(7);
        }
        try {
            // 从token中获取用户名
            String username = getUsernameFromToken(token);
            // 从token中获取claims
            Claims claims = getClaimsFromToken(token);
            // 判断用户名是否与userDetails中的用户名相同，并且token是否未过期
            return (username.equals(userDetails.getUsername()) && !isTokenExpired(claims));
        } catch (Exception e) {
            // 如果出现异常，则返回false
            return false;
        }
    }

    // 判断token是否过期
    private boolean isTokenExpired(Claims claims) {
        // 获取token的过期时间
        return claims.getExpiration().before(new Date());
    }

    /**
     * 从token中获取WebSocket认证信息
     */
    public Authentication getAuthenticationFromToken(String token) {
        try {
            // 从 token 中获取 Claims 对象
            Claims claims = getClaimsFromToken(token);
            // 如果 Claims 对象为空，则返回 null
            if (claims == null) {
                return null;
            }
            
            // 从 Claims 对象中获取用户名
            String username = claims.getSubject();
            // 根据用户名从 userDetailsService 中获取 UserDetails 对象
            UserDetails userDetails = userDetailsService.loadUserByUsername(username);
            
            // 如果 UserDetails 对象不是 SecurityUser 类型，则返回 null
            if (!(userDetails instanceof SecurityUser)) {
                log.warn("UserDetails 不是 SecurityUser 类型");
                return null;
            }
            
            // 返回一个新的 UsernamePasswordAuthenticationToken 对象
            return new UsernamePasswordAuthenticationToken(
                userDetails,
                null,
                userDetails.getAuthorities()
            );
        } catch (Exception e) {
            // 解析 token 失败，记录错误日志并返回 null
            log.error("解析 token 失败", e);
            return null;
        }
    }
} 